package edu.gyc.hiblog.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import edu.gyc.hiblog.model.Post;
import edu.gyc.hiblog.dao.PostDao;
import edu.gyc.hiblog.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.gyc.hiblog.util.RedisUtil;
import edu.gyc.hiblog.vo.PostVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ls
 * @since 2020-11-30
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostDao, Post> implements PostService {

    @Autowired
    PostDao postDao;

    @Autowired
    RedisUtil redisUtil;

    @Override
    public PageInfo<PostVo> paging(Integer pageNum) {
        PageHelper.startPage(pageNum, 2);
        List<PostVo> postVos = postDao.selectPostVos();
        PageInfo<PostVo> pageData = new PageInfo<>(postVos);

        return pageData;
    }

    @Override
    public PageInfo<PostVo> paging(Integer pageNum, Integer pageSize, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {
        PageHelper.startPage(pageNum, pageSize);
        List<PostVo> postVos = postDao.selectPostVosByCondition(categoryId, userId, level, recommend, order);
        PageInfo<PostVo> pageData = new PageInfo<>(postVos);

        return pageData;
    }

    @Override
    public PostVo selectOnePostVo(Long id) {
        return postDao.selectOnePostVo(id);
    }

    @Override
    public void initWeekRank() {
        List<Post> posts = this.lambdaQuery().ge(Post::getCreated, DateUtil.offsetDay(new Date(), -7)).list();

        for (Post post : posts) {
            String key = "day:rank:" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);
            redisUtil.zSet(key, post.getId(), post.getCommentCount());

            //7天后自动过期(15号发表，7-（18-15）=4）
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60; //有效时间
            redisUtil.expire(key, expireTime);
            //缓存文章的基本信息
            this.hashCachePostIdAndTitle(post, expireTime);
        }

        //做并集
        this.zunionStoreLast7DayForWeekRank();
    }

    @Override
    public void addCommentCountWeekRank(long postId, boolean isIncr) {
        String currentKey = "day:rank:" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
        redisUtil.zIncrementScore(currentKey,postId,isIncr?1:-1);


        Post post = getById(postId);
        //7天后自动过期(15号发表，7-（18-15）=4）
        long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
        long expireTime = (7 - between) * 24 * 60 * 60; //有效时间


        //缓存文章的基本信息
        this.hashCachePostIdAndTitle(post, expireTime);

        //重新做并集
        zunionStoreLast7DayForWeekRank();
    }

    @Override
    public void putViewCount(PostVo postVo) {
        String key="rank:post:"+postVo.getId();
        //从缓存中获取viewCount
        Integer viewCount = (Integer) redisUtil.hget(key, "post:viewCount");

        //若没有，从实体获取再加一
        if (viewCount != null) {
            postVo.setViewCount(viewCount+1);
        }else {
            postVo.setViewCount(postVo.getViewCount()+1);
        }
        //同步缓存
        redisUtil.hset(key, "post:viewCount", postVo.getViewCount());
    }

    //本周合并每日评论数量操作
    private void zunionStoreLast7DayForWeekRank() {
        String destKey = "day:rank:" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
        String key = "week:rank";
        List<String> otherKeys = new ArrayList<>();
        for (int i = -6; i < 0; i++) {
            String t = "day:rank:" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);
            otherKeys.add(t);
        }

        redisUtil.zUnionAndStore(destKey, otherKeys, key);
    }

    private void hashCachePostIdAndTitle(Post post, long expireTime) {
        String key = "rank:post:" + post.getId();
        boolean haskey = redisUtil.hasKey(key);
        if (!haskey) {
            redisUtil.hset(key, "post:id", post.getId(), expireTime);
            redisUtil.hset(key, "post:title", post.getTitle(), expireTime);
            redisUtil.hset(key, "post:commentCount", post.getCommentCount(), expireTime);
            redisUtil.hset(key, "post:viewCount", post.getViewCount(), expireTime);
        }
    }
}
